#include "GradientAction.h"
#include <QImage>
#include <cmath>
#include "Layer.h"
#include "Work.h"
#include "FilterLinear.h"



GradientAction::GradientAction () : AbstractAction (), _coreGenerator (NULL)
{

}

void GradientAction::updatePreview (QRect viewport)
{
	if (_coreGenerator == NULL)
		return;

	Ptr< Layer > pCurLayer = __pTargetWork->getDoc ()->getCurrentLayer ();

	bool isPreview = true;
	if (viewport.isEmpty ()) {
		isPreview = false;
		viewport = pCurLayer->getRegion ();
	}

	QRect updateRegion = viewport & pCurLayer->getRegion ();

	QPoint oSrcImg = pCurLayer->getRegion ().topLeft ();
	QPoint oViewport = viewport.topLeft ();
	QPoint oUpdate = updateRegion.topLeft ();

	QRect processRegion = updateRegion;
	processRegion.translate (-oSrcImg);

	Ptr< QImage > pProcessSrc = new QImage (pCurLayer->getImage ()
		->copy (processRegion));

	Ptr< QImage > pXImage = FilterLinear (_coreGenerator->getCore (-1, 0))
			.process (pProcessSrc);
	Ptr< QImage > pYImage = FilterLinear (_coreGenerator->getCore (-1, 1))
			.process (pProcessSrc);
	Ptr< QImage > pProcessResult = new QImage (processRegion.size (),
			QImage::Format_ARGB32);
	int maxVal = 0;
	for (int v = 0; v < pProcessResult->height (); ++v) {
		QRgb * srcXLine = (QRgb *)pXImage->scanLine (v);
		QRgb * srcYLine = (QRgb *)pYImage->scanLine (v);
		QRgb * resultLine = (QRgb *)pProcessResult->scanLine (v);
		for (int u = 0; u < pProcessResult->width ();++u) {
			int resultR = sqrtf (pow (float(qRed (srcXLine[u]) - 127), 2) +
					pow (float(qRed (srcYLine[u]) - 127), 2));
			if (resultR > maxVal)
				maxVal = resultR;
			int resultG = sqrtf (pow (float(qGreen (srcXLine[u]) - 127), 2) +
					pow (float(qRed (srcYLine[u]) - 127), 2));
			if (resultG > maxVal)
				maxVal = resultG;
			int resultB = sqrtf (pow (float(qBlue (srcXLine[u]) - 127), 2) +
					pow (float(qBlue (srcYLine[u]) - 127), 2));
			if (resultB > maxVal)
				maxVal = resultB;
			resultLine[u] = qRgba (resultR, resultG, resultB, 
					qAlpha (srcXLine[u]));
		}
	}
	float scale = 255.0 / maxVal;
	for (int v = 0; v < pProcessResult->height (); ++v) {
		QRgb * resultLine = (QRgb *)pProcessResult->scanLine (v);
		for (int u = 0; u < pProcessResult->width ();++u) {
			int resultR = scale * qRed (resultLine[u]);
			int resultG = scale * qGreen (resultLine[u]);
			int resultB = scale * qBlue (resultLine[u]);
			int resultA = qAlpha (resultLine[u]);
			resultLine[u] = qRgba (resultR, resultG, resultB, resultA);
		}
	}
	//Ptr< QImage > pProcessResult = _pFilter->process (pProcessSrc);

	if (isPreview)
		pCurLayer->setPreviewImage (pProcessResult);
	else
		pCurLayer->setImage (pProcessResult);

}

void GradientAction::handleStartEvent ()
{
	__pTargetWork->getDoc ()->getCurrentLayer ()->openPreview ();
}

void GradientAction::rejectAction ()
{
	__pTargetWork->getDoc ()->getCurrentLayer ()->closePreview ();
}

void GradientAction::applyAction ()
{
	updatePreview (QRect ());
	__pTargetWork->getDoc ()->getCurrentLayer ()->closePreview ();
}

void GradientAction::setCoreGenerator (Ptr< LinearCoreGenerator > coreGenerator)
{
	_coreGenerator = coreGenerator;
}
